#include "StdAfx.h"
#include "MappedFile.h"


MappedFile::MappedFile( wstring strFileName , long lSizeOfBuffer )
{
	DWORD dwFileSizeHigh;
	__int64 lSize;
	m_hFile = CreateFile( strFileName.c_str(), GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_FLAG_SEQUENTIAL_SCAN , NULL );
	if ( m_hFile == INVALID_HANDLE_VALUE )
		throw MAP_CANT_OPEN_FILE; // MAP_CANT_OPEN_FILE

	lSize = GetFileSize( m_hFile , &dwFileSizeHigh );
	lSize += (((__int64) dwFileSizeHigh) << 32);

		// Init map
	m_hFileMapping = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL); 
	if ( m_hFileMapping == NULL )
	{
			CloseHandle(m_hFile);
			m_hFile = INVALID_HANDLE_VALUE;
			throw MAP_CANT_ALLOCATE; // MAP_CANT_ALLOCATE
	}
	m_pBuffer = NULL;
	MapFilePart( 0 ); // Open first part of file
}


MappedFile::~MappedFile(void)
{
	if( m_pBuffer != NULL )
		UnmapViewOfFile( m_pBuffer );
	if( m_hFile != INVALID_HANDLE_VALUE )
		CloseHandle( m_hFile );
	if( m_hFileMapping != NULL )
		CloseHandle( m_hFileMapping );

}

void MappedFile::MapFilePart( long lShift )
{
	// unmap old mapping if exists
	if( m_pBuffer != NULL )
		UnmapViewOfFile( m_pBuffer );

	m_lShift = lShift;
	long lFileOffset = m_lSizeOfBuffer * m_lShift;
	// Calculate size of reading part to not leave the file
	long lBytesToRead = ((m_lFileSize - lFileOffset) < m_lSizeOfBuffer) ? (m_lFileSize - lFileOffset) : m_lSizeOfBuffer;
	// create mapping
	PBYTE pbFile = (PBYTE)MapViewOfFile(m_hFileMapping, FILE_MAP_READ, (DWORD) (lFileOffset >> 32) , (DWORD)(lFileOffset & 0xFFFFFFFF) , (DWORD)lBytesToRead );
	if( pbFile == NULL )
	{
		if( m_hFile != INVALID_HANDLE_VALUE )
			CloseHandle( m_hFile );
		if( m_hFileMapping != NULL )
			CloseHandle( m_hFileMapping );
		throw MAP_CANT_ALLOCATE; // MAP_CANT_ALLOCATE
	}
	m_pBuffer = (char*)pbFile;
	return;
}

char MappedFile::GetCharFromFile( long lPos )
{
	if( lPos >= m_lFileSize )
		throw -8; // MAP_LEAVED_BOUNDS

	// if we need another part of file - map it
	if( m_lShift != lPos / m_lSizeOfBuffer )
		MapFilePart( lPos / m_lSizeOfBuffer );

	lPos = lPos % m_lSizeOfBuffer;

	return m_pBuffer[ lPos ];
}

MapIterator MappedFile::Begin()
{
	return MapIterator( this , 0 );
}

MapIterator MappedFile::End()
{
	return MapIterator( this , m_lFileSize );
}

char MapIterator::operator*()
{
	return pMap->GetCharFromFile( m_pointer );
}
MapIterator::MapIterator( MappedFile* mapf , long pointer )
{
	pMap = mapf;
	m_pointer = pointer;
}
void MapIterator::operator++()
{
	m_pointer++;
	if( m_pointer > pMap->m_lFileSize )
		m_pointer = pMap->m_lFileSize;
}
bool MapIterator::operator == (MapIterator const& i)
{
	return (( pMap == i.pMap) && (m_pointer == i.m_pointer ));
}
bool MapIterator::operator != (MapIterator const& i)
{
	return (( pMap != i.pMap) || (m_pointer != i.m_pointer ));
}
MapIterator& MapIterator::operator =(const MapIterator& other)
{
	if (this != &other)
	{
		m_pointer = other.m_pointer;
		pMap = other.pMap;
	}
	return *this;
}